/** @jsxImportSource @emotion/react */
import * as React from "react";
import {
    Button, useTheme,
} from "customize-easy-ui-component";
import Uppy, {IndexedObject, SuccessResponse, UploadResult, UploadSuccessCallback, UppyFile} from "@uppy/core";
import Tus from "@uppy/tus";
import Webcam from "@uppy/webcam";
import useOssDeleteFileMutation from "../../hooks/useOssDeleteFileMutation";
import {Dashboard} from "@uppy/react";
import '@uppy/core/dist/style.min.css';
import '@uppy/dashboard/dist/style.min.css';
import '@uppy/webcam/dist/style.min.css';
import {tableSetInp} from "../../common/tool";
import {EditStorageContext} from "../StorageContext";

/**【uppy复用】
 *官方文档  https://uppy.io/docs/uppy/
 * */
//new实例：自带状态存储的；    不是React组件管理的。
const uppy =new Uppy({id:'Report', restrictions:{maxNumberOfFiles: 2,}})
    .use(Tus, { endpoint: `${process.env.REACT_APP_BACK_END}/uploadTUS/`, withCredentials:true,
        onAfterResponse: function (req, res) {
            let url =req.getURL();
            let value =res.getHeader("Tus2minIoUrl");       //对TUS协议还要自定义扩展的包头Tus2minIoUrl
            var occur = value?.indexOf("DO NOT TRY:");      //扩充包头含义。
            if(occur===0) {
                uppy.info("不要重试，报错" + value, "error", 999000);
                uppy.pauseAll();
            }else{
                let steob={} as any;
                steob[url]=value;
                uppy.setState({ ...steob});      //做关联映射TUS的id==>MinIO的下载链接。
            }
        }
    }).use(Webcam);

//加限制 restrictions:{maxFileSize: 6000,maxNumberOfFiles: 1, allowedFileTypes:['image/*', '.jpg', '.jpeg', '.png', '.gif']}
/**针对报告的 嵌入式的 文件上传。 针对与报告的 文件上传对象：
 * @param repId 分布式对象存储系统靠这个 rep ID来关联业务系统关系数据库的。
 * @param inp
 * @param setInp
 * @param field  存储上传后的文件对象信息对应inp字段。 _FILE_为前缀的；
 * @param maxFile  最多传几个文件； 依照maxFile=1来判定的json inp{}关联存储 _FILE_S 还是 _FILE_ 单个多个的分别。
 * @param maxSize  每一个文件大小最大 多少 MB 兆B单位。
 * 删除旧文件：关联的 rep+ repId必须的！
 * @param onSure 立刻生效给context 避免 事务性的缺失。
 * @param liveDays  该文件要求存储保留天数。 报告应该保留天数估计> 20年吧。
 * @return {} 节点DOM
 * */
export function useUppyUpload({ repId, inp, setInp, onSure, field,maxFile=1,liveDays=2,maxSize=3 }
    : {repId: string,inp: any, setInp:React.Dispatch<React.SetStateAction<any>>,
     onSure:(arg:any)=>void, field:string, maxFile?:number,liveDays?:number,maxSize?:number }
) {
    const theme= useTheme();
    const [openUppy, setOpenUppy] = React.useState(false);
    const [infiles, setInfiles] = React.useState<any[]>();
    React.useEffect(() => {
        uppy.setMeta({rep: repId, liveDays});
    }, [repId,liveDays]);
    //【上传应答】结束时刻回调，报错 unnecessary dependency: 'uppy'
    const handleUpSuccess = React.useCallback((result: { successful: any[]; }) => {
        let newUppsta=uppy.getState();
        const more= result.successful.map(up => {
            return {name: up.name, url: newUppsta[up.uploadURL], type: up.type}
        });
        const newarr=[...(infiles||[]), ...more];
        setInfiles(newarr);
    }, [infiles, setInfiles]);
    uppy.setOptions({
        restrictions: { maxNumberOfFiles: maxFile, maxFileSize: maxSize*1024*1024 },
        locale: {
            strings: {
                cancel: '还是取消',
            },
        },
    });
    uppy.on('complete', handleUpSuccess);

    //参数arIndex：回调时刻制定了 从哪一个文件index来触发删除后调用的。
    const whenDeleted= (reult: any,arIndex:number) => {
        if('成功'===reult || '不存在'===reult){
            if(1===maxFile)  setInp({ ...inp, [field]: undefined});
            else{
                inp?.[field]?.splice(arIndex,1);        //添加或删除数组中的元素。会改变原始数组。
                setInp({...inp});    //setInp({...inp,[field]:[...inp?.[field]] });
            }
        }
    };
    const {call:delOssFileFunc,doing:delOssing,result:delOssRs,called:delOssCald,reset:delOssRest}= useOssDeleteFileMutation(whenDeleted);

    //单一文件情况的：
    if(1===maxFile) {
      const onlyOne=(<>
        {openUppy?  <Dashboard uppy={uppy} plugins={['Webcam']} />
            :
            <div css={{display: 'flex',justifyContent: 'space-around',alignItems: 'center'}}>
                { inp?.[field]?.url &&
                    <img src={process.env.REACT_APP_OSS_ENDP+inp?.[field]?.url} alt={inp?.[field]?.url}
                         css={{
                             maxHeight: '14cm',   //在这个元素的上一级元素可以自己加一个固定高度值，就像一张纸打印的应该多高的取值。这个用固定高度会导致图片自动的横竖比例不均衡压缩=会变形啊！24cm是纸张大约最多高度=报告最大图片高。
                             maxWidth: '-webkit-fill-available',
                             "@media print": {maxHeight: '26cm', maxWidth: '705px'},         //对A4纸张竖版的高度26cm基本都是图片整张纸，这里没考虑多个图片在宽度方向上的并排布局：可用软件合并。
                             [theme.mediaQueries.lg]: {maxHeight: '18cm', maxWidth: undefined}           //普通图片+大屏幕限制高度才是关键的。
                         }}
                    />
                }
            </div>
        }
        <div css={{ textAlign: 'center',margin: theme.spaces.md}}>
            {
                 inp?.[field]?.url?  <Button css={{ marginTop: theme.spaces.sm }} size="sm"
                                              onPress={() =>delOssFileFunc(inp?.[field]?.url,0,'rep',repId) }
                        >旧的先刪除</Button>
                        :
                   <>
                        <Button css={{ marginTop: theme.spaces.sm }} size="sm"
                                onPress={() =>{
                                    setOpenUppy(!openUppy);
                                }}
                        >{openUppy? '关闭上传':'开启上传'}</Button>
                        <Button css={{ marginTop: theme.spaces.sm }} size="sm"  disabled={!infiles?.[0]}
                                onPress={ () => {
                                    setOpenUppy(false);
                                    const newfile=infiles?.map(({name,url}, i) => {
                                        return  (i<maxFile)&&{name,url}
                                    });
                                    if(1===maxFile) onSure( {...inp, [field]: newfile?.[0] || undefined} );
                                    else onSure( {...inp, [field]: newfile || undefined} );     //直接进行输入的确认操作！避免已上传的文件就被忽略不顾了。
                                }}
                        >文件输入确认</Button>
                  </>
            }
        </div>
     </>);

      return  [ onlyOne ];
    }
    else if(maxFile>1) {
        //允许有多个文件情况：类似 _FILE_部位 ； 多个文件存储的  _FILE_S部位 单一文件
        const manyMore = (<>
            <div css={{textAlign: 'center'}}>
                {
                    inp?.[field]?.map(({name, url}: any, i: number) => {
                        return <div key={i}>
                            <div css={{display: 'flex', justifyContent: 'space-around', alignItems: 'center'}}>
                                {url &&
                                    <img src={process.env.REACT_APP_OSS_ENDP + url} alt={url}
                                         css={{
                                             maxHeight: '14cm',   //在这个元素的上一级元素可以自己加一个固定高度值，就像一张纸打印的应该多高的取值。这个用固定高度会导致图片自动的横竖比例不均衡压缩=会变形啊！24cm是纸张大约最多高度=报告最大图片高。
                                             maxWidth: '-webkit-fill-available',
                                             "@media print": {maxHeight: '26cm', maxWidth: '705px'},         //对A4纸张竖版的高度26cm基本都是图片整张纸，这里没考虑多个图片在宽度方向上的并排布局：可用软件合并。
                                             [theme.mediaQueries.lg]: {maxHeight: '18cm', maxWidth: undefined}           //普通图片+大屏幕限制高度才是关键的。
                                         }}
                                    />
                                }
                            </div>
                            <Button css={{marginTop: theme.spaces.sm}} size="sm"
                                    onPress={() => delOssFileFunc(url, i, 'rep', repId)}
                            >旧的刪除</Button>
                        </div>
                    })
                }
            </div>
            <div css={{textAlign: 'center',margin: theme.spaces.md}}>
                {openUppy && <Dashboard uppy={uppy} plugins={['Webcam']}/>}
                <Button css={{marginTop: theme.spaces.sm}} size="sm"
                        onPress={() => {
                            setOpenUppy(!openUppy);
                        }}
                >{openUppy ? '关闭上传' : '开启上传'}</Button>
                <Button css={{marginTop: theme.spaces.sm}} size="sm" disabled={!infiles?.[0]}
                        onPress={() => {
                            setOpenUppy(false);
                            const newfile = infiles?.map(({name, url}, i) => {
                                return (i < maxFile) && {name, url}
                            }) as any;
                            if (1 === maxFile) onSure({...inp, [field]: newfile?.[0] || undefined});
                            else {
                                const mergedArr = [...(inp?.[field]??[]), ...newfile];
                                onSure({...inp, [field]: mergedArr});     //直接进行输入的确认操作！避免已上传的文件就被忽略不顾了。
                            }
                        }}
                >文件输入确认</Button>
            </div>
        </>);

      return [ manyMore ];
    }
    else return  [ ];
}
/**像管道单线图的这种上传：     【修订版】上传成功自动确认提交给storage存储，强制提示务必要保存当前storage给后端DB。
 * 约束条件？ EditStorageContext  setModified 移动到注入onSure回调。
 * @param repId 分布式对象存储系统靠这个 rep ID来关联业务系统关系数据库的。
 * @param table 表名：每次上传一个图片对应这里一个行。 row：包含不在这里编辑的字段。
 * @param field  图片存储在： 固定是； '_FILE_'
 * @param inp
 * @param setInp
 * @param row  那一个行的索引: 空表默认=0。【】每次上传唯一一个文件，而且针对特定row存储固定行位置。
 * @param maxSize  每一个文件大小最大 多少 MB 兆B单位。
 * 删除旧文件：关联的 rep+ repId必须的！
 * @param onFinish 立刻生效给context 避免 事务性的缺失。
 * @param liveDays  该文件要求存储保留天数。 报告应该保留天数估计> 20年吧。
 * @return {} 节点DOM
 * */
export function useUppyUploadDxt({ repId,table, field='_FILE_', inp, setInp, onFinish, row,liveDays=2,maxSize=3 }
                     : {repId: string,table:string,field?:string, inp: any, setInp:React.Dispatch<React.SetStateAction<any>>,
        onFinish:(row:number,file:any,del:boolean)=>void, row:number, liveDays?:number,maxSize?:number }
) {
    const theme= useTheme();
    const [openUppy, setOpenUppy] = React.useState(false);
    const [infiles, setInfiles] = React.useState<any[]>();
    // React.useEffect(() => {
    //     console.log("上传控件状态","infiles=",infiles, row,"uppy=",uppy );
    //     setInfiles([]);     //多个组件都有上传的 为何一进来 相互影响？
    //     // uppy.close({ reason: 'user' });
    // }, [row]);

    React.useEffect(() => {
        uppy.setMeta({rep: repId, liveDays});
    }, [repId,liveDays]);
    //报错 unnecessary dependency: 'uppy' ；[注意]这个回调若报错的，上传看似失败，实际OSS文件已经传完准备好了。
    const handleUpSuccess = React.useCallback((result: { successful: any[]; }) => {
        let newUppsta=uppy.getState();
        const more= result.successful.map(up => {
            return {name: up.name, url: newUppsta[up.uploadURL], type: up.type}
        });
        const newarr=[...(infiles||[]), ...more];
        setInfiles(newarr);
        if(newarr[0]){
            setOpenUppy(false);
            const newfile=newarr?.map(({name,url}, i) => {
                return  (i<1)&&{name,url}
            });
            console.log("onFinish 要执行",result.successful, row,"newUppsta",newUppsta);
            //if(!inp)    return;             //竟然还没有准备inp？？ 【问题大】handleUpSuccess会执行多次，多个组件混淆。
            onFinish(row,newfile?.[0] || undefined, false);
        }
    }, [infiles, row, onFinish, setInfiles]);

    uppy.setOptions({
        restrictions: { maxNumberOfFiles: 1, maxFileSize: maxSize*1024*1024 },
        locale: {
            strings: {
                cancel: '还是取消',
            },
        },
    });

    //complete: UploadCompleteCallback<TMeta>
    uppy.on('complete', handleUpSuccess);

    //下面这个却是：还没有真正上传完成的回调啊。
    //uppy.on('upload-success', handleUpSuccess2h);

    //【删除回调】参数arIndex：回调时刻制定了 从哪一个文件index来触发删除后调用的。 因为都是一个文件情况的：所以arIndex===0
    const whenDeleted= (reult: any,arIndex:number) => {
        if('成功'===reult || '不存在'===reult){
            const newobj={...inp?.[table]?.[row], [field]: undefined};
            tableSetInp(table, row, inp, setInp, field, newobj);
            onFinish(row, null, true);
            // else{
            //     inp?.[field]?.splice(arIndex,1);        //添加或删除数组中的元素。会改变原始数组。
            //     setInp({...inp});    //setInp({...inp,[field]:[...inp?.[field]] });
            // }
        }
    };
    const {call:delOssFileFunc,doing:delOssing,result:delOssRs,called:delOssCald,reset:delOssRest}= useOssDeleteFileMutation(whenDeleted);

    //单一文件情况的：
    const onlyOne=(<>
        {openUppy?  <Dashboard uppy={uppy} plugins={['Webcam']} />
            :
            <div css={{display: 'flex',justifyContent: 'space-around',alignItems: 'center'}}>
                { inp?.[table]?.[row]?.[field]?.url &&
                    <img src={process.env.REACT_APP_OSS_ENDP+inp?.[table]?.[row]?.[field]?.url} alt={inp?.[table]?.[row]?.[field]?.url}
                         css={{
                             maxHeight: '14cm',   //在这个元素的上一级元素可以自己加一个固定高度值，就像一张纸打印的应该多高的取值。这个用固定高度会导致图片自动的横竖比例不均衡压缩=会变形啊！24cm是纸张大约最多高度=报告最大图片高。
                             maxWidth: '-webkit-fill-available',
                             "@media print": {maxHeight: '26cm', maxWidth: '705px'},         //对A4纸张竖版的高度26cm基本都是图片整张纸，这里没考虑多个图片在宽度方向上的并排布局：可用软件合并。
                             [theme.mediaQueries.lg]: {maxHeight: '18cm', maxWidth: undefined}           //普通图片+大屏幕限制高度才是关键的。
                         }}
                    />
                }
            </div>
        }
        <div css={{ textAlign: 'center',margin: theme.spaces.md}}>
            {
                inp?.[table]?.[row]?.[field]?.url?  <Button css={{ marginTop: theme.spaces.sm }} size="sm"
                                            onPress={() =>delOssFileFunc(inp?.[table]?.[row]?.[field]?.url,0,'rep',repId) }
                    >旧的先刪除</Button>
                    :
                    <>
                        <Button css={{ marginTop: theme.spaces.sm }} size="sm"
                                onPress={() =>{
                                    setOpenUppy(!openUppy);
                                }}
                        >{openUppy? '关闭上传':'开启上传'}</Button>
                        <Button css={{ marginTop: theme.spaces.sm }} size="sm"  disabled={!infiles?.[0]}
                                onPress={ () => {
                                    setOpenUppy(false);
                                    const newfile=infiles?.map(({name,url}, i) => {
                                        return  (i<1)&&{name,url}
                                    });
                                    // onSure( {...inp, [field]: newfile?.[0] || undefined} );
                                    // tableSetInp(table, row, inp, onSure, field, newfile?.[0] || undefined);          //立即提交storage等着save给后端！
                                    // else onSure( {...inp, [field]: newfile || undefined} );     //直接进行输入的确认操作！避免已上传的文件就被忽略不顾了。
                                    onFinish(row, newfile?.[0] || undefined, false);
                                }}
                        >文件输入确认</Button>
                    </>
            }
        </div>
    </>);
    return  [ onlyOne ];
}

